package com.fansl.allround.common.security.provider;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.Assert;

/**
 * @author fansl
 * @Description: TODO
 * @date 2019/9/27 17:37
 */
@Slf4j
public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider {

    /**
     * 自定义认证校验
     * @param userDetails
     * @param authentication
     * @throws AuthenticationException
     */
    protected abstract void additionalAuthenticationChecks(UserDetails userDetails, Authentication authentication) throws AuthenticationException;

    /**
     * 权限认证
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getPrincipal() == null ? "NONE_PROVIDED" : authentication.getName();

        UserDetails user;
        try {
            user = this.retrieveUser(username,authentication);
        } catch (UsernameNotFoundException exception) {
            log.debug("User '" + username + "' not found");
            throw exception;
        }
        Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract");
        this.additionalAuthenticationChecks(user, authentication);
        return this.createSuccessAuthentication(authentication,user);
    }

    /**
     * 查找用户信息
     * @param username
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    protected abstract UserDetails retrieveUser(String username, Authentication authentication) throws AuthenticationException;

    /**
     * 生成认证信息
     * @param authentication
     * @param user
     * @return
     */
    protected abstract Authentication createSuccessAuthentication(Authentication authentication, UserDetails user);
}
